home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / pppipcp.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  31KB  |  1,192 lines

  1. /*
  2.  *  PPPIPCP.C    -- negotiate IP parameters
  3.  *
  4.  *    This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  *    Jan 91    Bill_Simpson@um.cc.umich.edu
  7.  *        Computer Systems Consulting Services
  8.  *
  9.  *    Acknowledgements and correction history may be found in PPP.C
  10.  *
  11.  *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  12.  */
  13.  
  14. /****************************************************************************
  15. *    $Id: pppipcp.c 1.4 93/07/16 11:49:12 ROOT_DOS Exp $
  16. *            1.2        MT    "time auto".                                        *
  17. *    14 Jul 93    1.3        GT    Fix warnings.                                    *
  18. ****************************************************************************/
  19.  
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <time.h>
  23. #include "global.h"
  24. #include "mbuf.h"
  25. #include "iface.h"
  26. #include "slhc.h"
  27. #include "ppp.h"
  28. #include "pppfsm.h"
  29. #include "pppipcp.h"
  30. #include "cmdparse.h"
  31. #include "files.h"
  32. #include "trace.h"
  33. #include "commands.h"
  34.  
  35. extern int done_set_time;
  36. extern char *Dscripts;
  37.  
  38. /* These defaults are defined in the PPP RFCs, and must not be changed */
  39. static struct ipcp_value_s ipcp_default = {
  40.     FALSE,            /* no need to negotiate defaults */
  41.  
  42.     0L,            /* no source address */
  43.     0L,            /* no destination address */
  44.  
  45.     0,            /* no compression protocol */
  46.     0,            /* no slots */
  47.     0            /* no slot compression */
  48. };
  49.  
  50. /* for test purposes, accept anything we understand */
  51. static int16 ipcp_negotiate = IPCP_N_ADDRESS | IPCP_N_COMPRESS;
  52.  
  53. static byte_t option_length[] = {
  54.      0,        /* unused */
  55.     10,        /* address */
  56.      6        /* compression */
  57. };
  58.  
  59. static void doscript        __ARGS((int direction, int32 address));
  60.  
  61. static int doipcp_local        __ARGS((int argc, char *argv[], void *p));
  62. static int doipcp_open        __ARGS((int argc, char *argv[], void *p));
  63. static int doipcp_pool        __ARGS((int argc, char *argv[], void *p));
  64. static int doipcp_remote    __ARGS((int argc, char *argv[], void *p));
  65.  
  66. static int doipcp_address    __ARGS((int argc, char *argv[], void *p));
  67. static int doipcp_compress    __ARGS((int argc, char *argv[], void *p));
  68. static int doipcp_default    __ARGS((int argc, char *argv[], void *p));
  69.  
  70. static void ipcp_option __ARGS((struct mbuf **bpp,
  71.             struct ipcp_value_s *value_p,
  72.             byte_t o_type,
  73.             byte_t o_length,
  74.             struct mbuf **copy_bpp));
  75. static void ipcp_makeoptions __ARGS((struct mbuf **bpp,
  76.             struct ipcp_value_s *value_p,
  77.             int16 negotiating));
  78. static struct mbuf *ipcp_makereq __ARGS((struct fsm_s *fsm_p));
  79.  
  80. static int ipcp_check __ARGS((struct mbuf **bpp,
  81.             struct ipcp_s *ipcp_p,
  82.             struct ipcp_side_s *side_p,
  83.             struct option_hdr *option_p,
  84.             int request));
  85.  
  86. static int ipcp_request    __ARGS((struct fsm_s *fsm_p,
  87.             struct config_hdr *config,
  88.             struct mbuf *data));
  89. static int ipcp_ack    __ARGS((struct fsm_s *fsm_p,
  90.             struct config_hdr *config,
  91.             struct mbuf *data));
  92. static int ipcp_nak    __ARGS((struct fsm_s *fsm_p,
  93.             struct config_hdr *config,
  94.             struct mbuf *data));
  95. static int ipcp_reject    __ARGS((struct fsm_s *fsm_p,
  96.             struct config_hdr *config,
  97.             struct mbuf *data));
  98.  
  99. static void ipcp_reset    __ARGS((struct fsm_s *fsm_p));
  100.  
  101. static int32 ipcp_addr_idle __ARGS((int32 addr));
  102. static int32 ipcp_lookuppeer __ARGS((char *peerid));
  103. static int32 ipcp_poolnext __ARGS((struct ipcp_s *ipcp_p));
  104.  
  105. static void ipcp_starting __ARGS((struct fsm_s *fsm_p));
  106. static void ipcp_stopping __ARGS((struct fsm_s *fsm_p));
  107.  
  108. static void ipcp_closing __ARGS((struct fsm_s *fsm_p));
  109. static void ipcp_opening __ARGS((struct fsm_s *fsm_p));
  110.  
  111. static void ipcp_free    __ARGS((struct fsm_s *fsm_p));
  112.  
  113.  
  114. static struct fsm_constant_s ipcp_constants = {
  115.     "IPcp",
  116.     PPP_IPCP_PROTOCOL,
  117.     0x00FE,                /* codes 1-7 recognized */
  118.  
  119.     IPcp,
  120.     IPCP_REQ_TRY,
  121.     IPCP_NAK_TRY,
  122.     IPCP_TERM_TRY,
  123.     IPCP_TIMEOUT * 1000L,
  124.  
  125.     ipcp_free,
  126.  
  127.     ipcp_reset,
  128.     ipcp_starting,
  129.     ipcp_opening,
  130.     ipcp_closing,
  131.     ipcp_stopping,
  132.  
  133.     ipcp_makereq,
  134.     ipcp_request,
  135.     ipcp_ack,
  136.     ipcp_nak,
  137.     ipcp_reject,
  138. };
  139.  
  140.  
  141. /************************************************************************/
  142.  
  143. /* "ppp <iface> ipcp" subcommands */
  144. static struct cmds IPcpcmds[] = {
  145.     { "close",    doppp_close,    0,    0,    NULLCHAR },
  146.     { "listen",    doppp_passive,    0,    0,    NULLCHAR },
  147.     { "local",    doipcp_local,    0,    0,    NULLCHAR },
  148.     { "open",        doipcp_open,    0,    0,    NULLCHAR },
  149.     { "pool",        doipcp_pool,    0,    0,    NULLCHAR },
  150.     { "remote",    doipcp_remote,    0,    0,    NULLCHAR },
  151.     { "timeout",    doppp_timeout,    0,    0,    NULLCHAR },
  152.     { "try",        doppp_try,    0,    0,    NULLCHAR },
  153.     { NULLCHAR },
  154. };
  155.  
  156. /* "ppp <iface> ipcp {local | remote}" subcommands */
  157. static struct cmds IPcpside_cmds[] = {
  158.     { "address",    doipcp_address,    0,    0,    NULLCHAR },
  159.     { "compress",    doipcp_compress,0,    0,    NULLCHAR },
  160.     { "default",    doipcp_default,    0,    0,    NULLCHAR },
  161.     { NULLCHAR },
  162. };
  163.  
  164.  
  165. int
  166. doppp_ipcp(argc,argv,p)
  167. int argc;
  168. char *argv[];
  169. void *p;
  170. {
  171.     register struct iface *ifp = p;
  172.     register struct ppp_s *ppp_p = ifp->edv;
  173.  
  174.     return subcmd(IPcpcmds, argc, argv, &(ppp_p->fsm[IPcp]));
  175. }
  176.  
  177.  
  178. static int
  179. doipcp_local(argc,argv,p)
  180. int argc;
  181. char *argv[];
  182. void *p;
  183. {
  184.     struct fsm_s *fsm_p = p;
  185.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  186.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->local));
  187. }
  188.  
  189.  
  190. static int
  191. doipcp_open(argc,argv,p)
  192. int argc;
  193. char *argv[];
  194. void *p;
  195. {
  196.     struct fsm_s *fsm_p = p;
  197.  
  198.     doppp_active( argc, argv, p );
  199.  
  200.     if ( fsm_p->ppp_p->phase == pppREADY ) {
  201.         fsm_start( fsm_p );
  202.     }
  203.     return 0;
  204. }
  205.  
  206.  
  207. /* Set a pool of peer addresses for PPP interface */
  208. static int
  209. doipcp_pool(argc,argv,p)
  210. int argc;
  211. char *argv[];
  212. void *p;
  213. {
  214.     struct fsm_s *fsm_p = p;
  215.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  216.     int32 pool_addr;
  217.     int pool_cnt;
  218.  
  219.     if (argc < 2) {
  220.         if ( ipcp_p->peer_min == 0L ) {
  221.             tprintf("None");
  222.         } else {
  223.             tprintf("%s thru ", inet_ntoa(ipcp_p->peer_min));
  224.             tprintf("%s\n", inet_ntoa(ipcp_p->peer_max));
  225.         }
  226.         return 0;
  227.     }
  228.  
  229.     if ((pool_addr = resolve(argv[1])) == 0L) {
  230.         tprintf(Badhost,argv[1]);
  231.     }
  232.  
  233.     /* May specify a consecutive range of addresses; otherwise assume 1 */
  234.     if (argc < 3)
  235.         pool_cnt = 1;
  236.     else
  237.         pool_cnt = (int)strtol( argv[2], NULLCHARP, 0 );
  238.  
  239.     if (pool_cnt <= 0) {
  240.         tprintf("Pool count %s (%d) must be > 0\n");
  241.         return -1;
  242.     }
  243.  
  244.     ipcp_p->peer_min = pool_addr;
  245.     ipcp_p->peer_max = pool_addr + pool_cnt - 1;
  246.     return 0;
  247. }
  248.  
  249.  
  250. static int
  251. doipcp_remote(argc,argv,p)
  252. int argc;
  253. char *argv[];
  254. void *p;
  255. {
  256.     struct fsm_s *fsm_p = p;
  257.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  258.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->remote));
  259. }
  260.  
  261.  
  262. /************************************************************************/
  263. /* Set addresses for PPP interface */
  264. static int
  265. doipcp_address(argc,argv,p)
  266. int argc;
  267. char *argv[];
  268. void *p;
  269. {
  270.     struct ipcp_side_s *side_p = p;
  271.     int32 x32;
  272.  
  273.     if (argc < 2) {
  274.         tprintf("%s\n", inet_ntoa(side_p->want.address));
  275.         return 0;
  276.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  277.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_ADDRESS,
  278.             "Allow Address", --argc, &argv[1] );
  279.     }
  280.     if ((x32 = resolve(argv[1])) == 0L) {
  281.         tprintf(Badhost,argv[1]);
  282.     }
  283.     side_p->want.address = x32;
  284.     side_p->want.negotiate |= IPCP_N_ADDRESS;
  285.     return 0;
  286. }
  287.  
  288.  
  289. /* Set IP compression type for PPP interface */
  290. static int
  291. doipcp_compress(argc,argv,p)
  292. int argc;
  293. char *argv[];
  294. void *p;
  295. {
  296.     struct ipcp_side_s *side_p = p;
  297.  
  298.     if (argc < 2) {
  299.         if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  300.             switch ( side_p->want.compression ) {
  301.             case PPP_COMPR_PROTOCOL:
  302.                 tprintf("TCP header compression enabled; "
  303.                     "Slots = %d, slot compress = %x\n",
  304.                     side_p->want.slots,
  305.                     side_p->want.slot_compress);
  306.                 break;
  307.             default:
  308.                 tprintf("0x%04x\n", side_p->want.compression);
  309.                 break;
  310.             };
  311.         } else {
  312.             tprintf("None\n");
  313.         }
  314.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  315.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_COMPRESS,
  316.             "Allow Compression", --argc, &argv[1] );
  317.     } else if ( stricmp(argv[1],"tcp") == 0
  318.          || stricmp(argv[1],"vj") == 0 ) {
  319.         side_p->want.compression = PPP_COMPR_PROTOCOL;
  320.         if ( argc >= 3 ) {
  321.             side_p->want.slots = strtol(argv[2],NULLCHARP,0);
  322.             if ( side_p->want.slots < 1 || side_p->want.slots > 255 ) {
  323.                 tprintf( "slots must be in range 1 to 255" );
  324.                 return 1;
  325.             }
  326.         } else {
  327.             side_p->want.slots = IPCP_SLOT_DEFAULT;
  328.         }
  329.         if ( argc >= 4 ) {
  330.             side_p->want.slot_compress = strtol(argv[3],NULLCHARP,0);
  331.         } else {
  332.             side_p->want.slot_compress = IPCP_SLOT_COMPRESS;
  333.         }
  334.         side_p->want.negotiate |= IPCP_N_COMPRESS;
  335.     } else if (stricmp(argv[1],"none") == 0) {
  336.         side_p->want.negotiate &= ~IPCP_N_COMPRESS;
  337.     } else {
  338.         tprintf("allow tcp none\n");
  339.         return 1;
  340.     }
  341.     return 0;
  342. }
  343.  
  344.  
  345. static int
  346. doipcp_default(argc,argv,p)
  347. int argc;
  348. char *argv[];
  349. void *p;
  350. {
  351.     struct ipcp_side_s *side_p = p;
  352.  
  353.     ASSIGN( side_p->want, ipcp_default );
  354.     return 0;
  355. }
  356.  
  357.  
  358. /************************************************************************/
  359. /*            E V E N T   P R O C E S S I N G            */
  360. /************************************************************************/
  361.  
  362. static void ipcp_option(
  363.     struct mbuf **bpp,
  364.     struct ipcp_value_s *value_p,
  365.     byte_t o_type,
  366.     byte_t o_length,
  367.     struct mbuf **copy_bpp )
  368. {
  369.     struct mbuf *bp;
  370.     register char *cp;
  371.     register int toss = o_length - OPTION_HDR_LEN;
  372.  
  373.     if ((bp = alloc_mbuf(o_length)) == NULLBUF) {
  374.         return;
  375.     }
  376.     cp = bp->data;
  377.     *cp++ = o_type;
  378.     *cp++ = o_length;
  379.  
  380.     switch ( o_type ) {
  381.     case IPCP_ADDRESS:
  382.         cp = put32(cp, value_p->address);
  383.         cp = put32(cp, value_p->other);
  384.         toss -= 8;
  385. #ifdef PPP_DEBUG_OPTIONS
  386. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  387.     trace_log(PPPiface, "    making IP source address: %s",
  388.         inet_ntoa(value_p->address));
  389.     trace_log(PPPiface, "    making IP destination address %s",
  390.         inet_ntoa(value_p->other));
  391. }
  392. #endif
  393.         break;
  394.  
  395.     case IPCP_COMPRESS:
  396.         cp = put16(cp, value_p->compression);
  397.         toss -= 2;
  398. #ifdef PPP_DEBUG_OPTIONS
  399. if (PPPtrace & PPP_DEBUG_OPTIONS)
  400.     trace_log(PPPiface, "    making IP compression 0x%04x",
  401.         value_p->compression);
  402. #endif
  403.         if ( value_p->compression == PPP_COMPR_PROTOCOL ) {
  404.             *cp++ = value_p->slots - 1;
  405.             *cp++ = value_p->slot_compress;
  406.             toss -= 2;
  407. #ifdef PPP_DEBUG_OPTIONS
  408. if (PPPtrace & PPP_DEBUG_OPTIONS)
  409.     trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  410.         value_p->slots,
  411.         value_p->slot_compress);
  412. #endif
  413.         }
  414.         break;
  415.  
  416.     default:
  417. #ifdef PPP_DEBUG_OPTIONS
  418. if (PPPtrace & PPP_DEBUG_OPTIONS)
  419.     trace_log(PPPiface, "    making unimplemented type %d", o_type);
  420. #endif
  421.         break;
  422.     };
  423.  
  424.     while ( toss-- > 0 ) {
  425.         *cp++ = pullchar(copy_bpp);
  426.     }
  427.     bp->cnt += o_length;
  428.     append(bpp, bp);
  429. }
  430.  
  431.  
  432. /************************************************************************/
  433. /* Build a list of options */
  434.  
  435. static void ipcp_makeoptions(
  436.     struct mbuf **bpp,
  437.     struct ipcp_value_s *value_p,
  438.     int16 negotiating )
  439. {
  440.     register int o_type;
  441.  
  442.     PPP_DEBUG_ROUTINES("ipcp_makeoptions()");
  443.  
  444.     for ( o_type = 1; o_type <= IPCP_OPTION_LIMIT; o_type++ ) {
  445.         if (negotiating & (1 << o_type)) {
  446.             ipcp_option( bpp, value_p,
  447.                 o_type, option_length[ o_type ], NULLBUFP);
  448.         }
  449.     }
  450. }
  451.  
  452.  
  453. /************************************************************************/
  454. /* Build a request to send to remote host */
  455. static struct mbuf *
  456. ipcp_makereq(fsm_p)
  457. struct fsm_s *fsm_p;
  458. {
  459.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  460.     struct mbuf *req_bp = NULLBUF;
  461.  
  462.     PPP_DEBUG_ROUTINES("ipcp_makereq()");
  463.  
  464.     ipcp_makeoptions( &req_bp, &(ipcp_p->local.work),
  465.                 ipcp_p->local.work.negotiate );
  466.     return(req_bp);
  467. }
  468.  
  469.  
  470. /************************************************************************/
  471. /* Check the options, updating the working values.
  472.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  473.  */
  474. static int
  475. ipcp_check( bpp, ipcp_p, side_p, option_p, request )
  476. struct mbuf **bpp;
  477. struct ipcp_s *ipcp_p;
  478. struct ipcp_side_s *side_p;
  479. struct option_hdr *option_p;
  480. int request;
  481. {
  482.     int toss = option_p->len - OPTION_HDR_LEN;
  483.     int option_result = CONFIG_ACK;        /* Assume good values */
  484.     int test;
  485.  
  486.     switch(option_p->type) {
  487.     case IPCP_ADDRESS:
  488.         side_p->work.address = pull32(bpp);
  489.         side_p->work.other = pull32(bpp);
  490.         toss -= 8;
  491. #ifdef PPP_DEBUG_OPTIONS
  492. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  493.     trace_log(PPPiface, "    checking IP source address: %s",
  494.         inet_ntoa(side_p->work.address));
  495.     trace_log(PPPiface, "    checking IP destination address %s",
  496.         inet_ntoa(side_p->work.other));
  497. }
  498. #endif
  499.         if ( !request ) {
  500.             /* override any undesirable changes */
  501.             if (ipcp_p->remote.want.address != 0L) {
  502.                 ipcp_p->local.work.other
  503.                     = ipcp_p->remote.want.address;
  504.             }
  505.             if (ipcp_p->local.want.address != 0L) {
  506.                 ipcp_p->local.work.address
  507.                     = ipcp_p->local.want.address;
  508.             }
  509.             break;
  510.         }
  511.  
  512.         /* Ensure that addresses match */
  513.         if (ipcp_p->remote.work.address == ipcp_p->remote.want.address) {
  514.             if (ipcp_p->remote.want.address == 0L) {
  515.                 /* don't know address either */
  516.                 option_result = CONFIG_REJ;
  517.             }
  518.         } else if (ipcp_p->remote.want.address == 0L) {
  519.             ipcp_p->local.work.other = ipcp_p->remote.work.address;
  520.         } else {
  521.             ipcp_p->remote.work.address = ipcp_p->remote.want.address;
  522.             option_result = CONFIG_NAK;
  523.         }
  524.  
  525.         if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
  526.             if (ipcp_p->local.want.address == 0L) {
  527.                 /* don't know address either */
  528.                 option_result = CONFIG_REJ;
  529.             }
  530.         } else if (ipcp_p->local.want.address == 0L) {
  531.             ipcp_p->local.work.address = ipcp_p->remote.work.other;
  532.         } else {
  533.             option_result = CONFIG_NAK;
  534.             ipcp_p->remote.work.other = ipcp_p->local.want.address;
  535.         }
  536.         break;
  537.  
  538.     case IPCP_COMPRESS:
  539.         side_p->work.compression = pull16(bpp);
  540.         toss -= 2;
  541. #ifdef PPP_DEBUG_OPTIONS
  542. if (PPPtrace & PPP_DEBUG_OPTIONS)
  543.     trace_log(PPPiface, "    checking IP compression 0x%04x",
  544.         side_p->work.compression);
  545. #endif
  546.         /* Check if requested type is acceptable */
  547.         switch ( side_p->work.compression ) {
  548.         case PPP_COMPR_PROTOCOL:
  549.             if ( (test = pullchar(bpp)) == -1 ) {
  550.                 return -1;
  551.             }
  552.             if ( (side_p->work.slots = test + 1) < IPCP_SLOT_LO) {
  553.                 side_p->work.slots = IPCP_SLOT_LO;
  554.                 option_result = CONFIG_NAK;
  555.             } else if (side_p->work.slots > IPCP_SLOT_HI) {
  556.                 side_p->work.slots = IPCP_SLOT_HI;
  557.                 option_result = CONFIG_NAK;
  558.             }
  559.  
  560.             if ( (test = pullchar(bpp)) == -1 ) {
  561.                 return -1;
  562.             }
  563.             if ( (side_p->work.slot_compress = test) > 1 ) {
  564.                 side_p->work.slot_compress = 1;
  565.                 option_result = CONFIG_NAK;
  566.             }
  567.             toss -= 2;
  568. #ifdef PPP_DEBUG_OPTIONS
  569. if (PPPtrace & PPP_DEBUG_OPTIONS)
  570.     trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  571.         side_p->work.slots,
  572.         side_p->work.slot_compress);
  573. #endif
  574.             break;
  575.  
  576.         default:
  577.             if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  578.                 side_p->work.compression = side_p->want.compression;
  579.                 side_p->work.slots = side_p->want.slots;
  580.                 side_p->work.slot_compress = side_p->want.slot_compress;
  581.             } else {
  582.                 side_p->work.compression = PPP_COMPR_PROTOCOL;
  583.                 side_p->work.slots = IPCP_SLOT_DEFAULT;
  584.                 side_p->work.slot_compress = IPCP_SLOT_COMPRESS;
  585.             }
  586.             option_result = CONFIG_NAK;
  587.             break;
  588.         };
  589.         break;
  590.  
  591.     default:
  592.         option_result = CONFIG_REJ;
  593.         break;
  594.     };
  595.  
  596.     if (option_p->type > IPCP_OPTION_LIMIT
  597.      || !(side_p->will_negotiate & (1 << option_p->type))) {
  598.         option_result = CONFIG_REJ;
  599.     }
  600.  
  601.     if ( toss < 0 )
  602.         return -1;
  603.  
  604.     if ( !request  &&  toss > 0 ) {
  605.         /* toss extra bytes in option */
  606.         while( toss-- > 0 ) {
  607.             if ( pullchar(bpp) == -1 )
  608.                 return -1;
  609.         }
  610.     }
  611.  
  612.     return (option_result);
  613. }
  614.  
  615.  
  616. /************************************************************************/
  617. /* Check options requested by the remote host */
  618. static int
  619. ipcp_request(fsm_p, config, data)
  620. struct fsm_s *fsm_p;
  621. struct config_hdr *config;
  622. struct mbuf *data;
  623. {
  624.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  625.     int32 signed_length = config->len;
  626.     struct mbuf *reply_bp = NULLBUF;    /* reply packet */
  627.     int reply_result = CONFIG_ACK;        /* reply to request */
  628.     int16 desired;                /* desired to negotiate */
  629.     struct option_hdr option;        /* option header storage */
  630.     int option_result;            /* option reply */
  631.  
  632.     PPP_DEBUG_ROUTINES("ipcp_request()");
  633.     ipcp_p->remote.work.negotiate = FALSE;    /* clear flags */
  634.  
  635.     /* Process options requested by remote host */
  636.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  637.         if ((signed_length -= option.len) < 0) {
  638.             PPP_DEBUG_CHECKS("IPCP REQ: bad header length");
  639.             free_p(data);
  640.             free_p(reply_bp);
  641.             return -1;
  642.         }
  643.  
  644.         if ( ( option_result = ipcp_check( &data, ipcp_p,
  645.                 &(ipcp_p->remote), &option, TRUE ) ) == -1 ) {
  646.             PPP_DEBUG_CHECKS("IPCP REQ: ran out of data");
  647.             free_p(data);
  648.             free_p(reply_bp);
  649.             return -1;
  650.         }
  651.  
  652. #ifdef PPP_DEBUG_OPTIONS
  653. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  654.     trace_log(PPPiface, "IPCP REQ: result %s, option %d, length %d",
  655.         fsmCodes[option_result],
  656.         option.type,
  657.         option.len);
  658. }
  659. #endif
  660.         if ( option_result < reply_result ) {
  661.             continue;
  662.         } else if ( option_result > reply_result ) {
  663.             /* Discard current list of replies */
  664.             free_p(reply_bp);
  665.             reply_bp = NULLBUF;
  666.             reply_result = option_result;
  667.         }
  668.  
  669.         /* remember that we processed option */
  670.         if ( option_result != CONFIG_REJ
  671.          && option.type <= IPCP_OPTION_LIMIT ) {
  672.             ipcp_p->remote.work.negotiate |= (1 << option.type);
  673.         }
  674.  
  675.         /* Add option response to the return list */
  676.         ipcp_option( &reply_bp, &(ipcp_p->remote.work),
  677.             option.type, option.len, &data );
  678.     }
  679.  
  680.     /* Now check for any missing options which are desired */
  681.     if ( fsm_p->retry_nak > 0
  682.      &&  (desired = ipcp_p->remote.want.negotiate
  683.                & ~ipcp_p->remote.work.negotiate) != 0 ) {
  684.         switch ( reply_result ) {
  685.         case CONFIG_ACK:
  686.             free_p(reply_bp);
  687.             reply_bp = NULLBUF;
  688.             reply_result = CONFIG_NAK;
  689.             /* fallthru */
  690.         case CONFIG_NAK:
  691.             ipcp_makeoptions( &reply_bp, &(ipcp_p->remote.want),
  692.                 desired );
  693.             fsm_p->retry_nak--;
  694.             break;
  695.         case CONFIG_REJ:
  696.             /* do nothing */
  697.             break;
  698.         };
  699.     } else if ( reply_result == CONFIG_NAK ) {
  700.         /* if too many NAKs, reject instead */
  701.         if ( fsm_p->retry_nak > 0 )
  702.             fsm_p->retry_nak--;
  703.         else
  704.             reply_result = CONFIG_REJ;
  705.     }
  706.  
  707.     /* Send ACK/NAK/REJ to remote host */
  708.     fsm_send(fsm_p, reply_result, config->id, reply_bp);
  709.     free_p(data);
  710.     return (reply_result != CONFIG_ACK);
  711. }
  712.  
  713.  
  714. /************************************************************************/
  715. /* Process configuration ACK sent by remote host */
  716. static int
  717. ipcp_ack(fsm_p, config, data)
  718. struct fsm_s *fsm_p;
  719. struct config_hdr *config;
  720. struct mbuf *data;
  721. {
  722.     struct mbuf *req_bp;
  723.     int error = FALSE;
  724.  
  725.     PPP_DEBUG_ROUTINES("ipcp_ack()");
  726.  
  727.     /* ID field must match last request we sent */
  728.     if (config->id != fsm_p->lastid) {
  729.         PPP_DEBUG_CHECKS("IPCP ACK: wrong ID");
  730.         free_p(data);
  731.         return -1;
  732.     }
  733.  
  734.     /* Get a copy of last request we sent */
  735.     req_bp = ipcp_makereq(fsm_p);
  736.  
  737.     /* Overall buffer length should match */
  738.     if (config->len != len_p(req_bp)) {
  739.         PPP_DEBUG_CHECKS("IPCP ACK: buffer length mismatch");
  740.         error = TRUE;
  741.     } else {
  742.         register int req_char;
  743.         register int ack_char;
  744.  
  745.         /* Each byte should match */
  746.         while ((req_char = pullchar(&req_bp)) != -1) {
  747.             if ((ack_char = pullchar(&data)) == -1
  748.              || ack_char != req_char ) {
  749.                 PPP_DEBUG_CHECKS("IPCP ACK: data mismatch");
  750.                 error = TRUE;
  751.                 break;
  752.             }
  753.         }
  754.     }
  755.     free_p(req_bp);
  756.     free_p(data);
  757.  
  758.     if (error) {
  759.         return -1;
  760.     }
  761.  
  762.     PPP_DEBUG_CHECKS("IPCP ACK: valid");
  763.     return 0;
  764. }
  765.  
  766.  
  767. /************************************************************************/
  768. /* Process configuration NAK sent by remote host */
  769. static int
  770. ipcp_nak(fsm_p, config, data)
  771. struct fsm_s *fsm_p;
  772. struct config_hdr *config;
  773. struct mbuf *data;
  774. {
  775.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  776.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  777.     int32 signed_length = config->len;
  778.     struct option_hdr option;
  779.     int last_option = 0;
  780.     int result;
  781.  
  782.     PPP_DEBUG_ROUTINES("ipcp_nak()");
  783.  
  784.     /* ID field must match last request we sent */
  785.     if (config->id != fsm_p->lastid) {
  786.         PPP_DEBUG_CHECKS("IPCP NAK: wrong ID");
  787.         free_p(data);
  788.         return -1;
  789.     }
  790.  
  791.     /* First, process in order.  Then, process extra "important" options */
  792.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  793.         if ((signed_length -= option.len) < 0) {
  794.             PPP_DEBUG_CHECKS("IPCP NAK: bad header length");
  795.             free_p(data);
  796.             return -1;
  797.         }
  798.         if ( option.type > IPCP_OPTION_LIMIT ) {
  799.             PPP_DEBUG_CHECKS("IPCP NAK: option out of range");
  800.         } else if ( option.type < last_option
  801.          || !(local_p->work.negotiate & (1 << option.type)) ) {
  802.             if (local_p->work.negotiate & (1 << option.type)) {
  803.                 PPP_DEBUG_CHECKS("IPCP NAK: option out of order");
  804.                 free_p(data);
  805.                 return -1;        /* was requested */
  806.             }
  807.             local_p->work.negotiate |= (1 << option.type);
  808.             last_option = IPCP_OPTION_LIMIT + 1;
  809.         } else {
  810.             last_option = option.type;
  811.         }
  812.         if ( ( result = ipcp_check( &data, ipcp_p,
  813.                 local_p, &option, FALSE ) ) == -1 ) {
  814.             PPP_DEBUG_CHECKS("IPCP NAK: ran out of data");
  815.             free_p(data);
  816.             return -1;
  817.         }
  818.         /* update the negotiation status */
  819.         if ( result == CONFIG_REJ
  820.           && option.type <= IPCP_OPTION_LIMIT ) {
  821.             local_p->work.negotiate &= ~(1 << option.type);
  822.         }
  823.     }
  824.     PPP_DEBUG_CHECKS("IPCP NAK: valid");
  825.     free_p(data);
  826.     return 0;
  827. }
  828.  
  829.  
  830. /************************************************************************/
  831. /* Process configuration reject sent by remote host */
  832. static int
  833. ipcp_reject(fsm_p, config, data)
  834. struct fsm_s *fsm_p;
  835. struct config_hdr *config;
  836. struct mbuf *data;
  837. {
  838.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  839.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  840.     int32 signed_length = config->len;
  841.     struct option_hdr option;
  842.     int last_option = 0;
  843.  
  844.     PPP_DEBUG_ROUTINES("ipcp_reject()");
  845.  
  846.     /* ID field must match last request we sent */
  847.     if (config->id != fsm_p->lastid) {
  848.         PPP_DEBUG_CHECKS("IPCP REJ: wrong ID");
  849.         free_p(data);
  850.         return -1;
  851.     }
  852.  
  853.     /* Process in order, checking for errors */
  854.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  855.         register int k;
  856.  
  857.         if ((signed_length -= option.len) < 0) {
  858.             PPP_DEBUG_CHECKS("IPCP REJ: bad header length");
  859.             free_p(data);
  860.             return -1;
  861.         }
  862.         if ( option.type > IPCP_OPTION_LIMIT ) {
  863.             PPP_DEBUG_CHECKS("IPCP REJ: option out of range");
  864.         } else if (option.type < last_option
  865.          || !(local_p->work.negotiate & (1 << option.type))) {
  866.             PPP_DEBUG_CHECKS("IPCP REJ: option out of order");
  867.             free_p(data);
  868.             return -1;
  869.         }
  870.         for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
  871.             if ( pullchar(&data) == -1 ) {
  872.                 PPP_DEBUG_CHECKS("IPCP REJ: ran out of data");
  873.                 free_p(data);
  874.                 return -1;
  875.             }
  876.         }
  877.         last_option = option.type;
  878.  
  879.         if ( option.type <= IPCP_OPTION_LIMIT ) {
  880.             local_p->work.negotiate &= ~(1 << option.type);
  881.         }
  882.     }
  883.     PPP_DEBUG_CHECKS("IPCP REJ: valid");
  884.     free_p(data);
  885.     return 0;
  886. }
  887.  
  888.  
  889. /************************************************************************/
  890. /*            I N I T I A L I Z A T I O N            */
  891. /************************************************************************/
  892.  
  893. /* Reset configuration options before request */
  894. static void
  895. ipcp_reset(fsm_p)
  896. struct fsm_s *fsm_p;
  897. {
  898.     struct ipcp_s *ipcp_p =    fsm_p->pdv;
  899.  
  900.     PPP_DEBUG_ROUTINES("ipcp_reset()");
  901.  
  902.     ASSIGN( ipcp_p->local.work, ipcp_p->local.want );
  903.     ipcp_p->local.work.other = ipcp_p->remote.want.address;
  904.     ipcp_p->local.will_negotiate |= ipcp_p->local.want.negotiate;
  905.  
  906.     ipcp_p->remote.work.negotiate = FALSE;
  907.     ipcp_p->remote.will_negotiate |= ipcp_p->remote.want.negotiate;
  908. }
  909.  
  910.  
  911. /************************************************************************/
  912. /* After termination */
  913. static void
  914. ipcp_stopping(fsm_p)
  915. struct fsm_s *fsm_p;
  916. {
  917.     PPP_DEBUG_ROUTINES("ipcp_stopping()");
  918. }
  919.  
  920.  
  921. /************************************************************************/
  922. /* Close IPCP */
  923. static void
  924. ipcp_closing(fsm_p)
  925. struct fsm_s *fsm_p;
  926. {
  927.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  928.  
  929.     /* free old slhc configuration, if any */
  930.     slhc_free( ipcp_p->slhcp );
  931.     ipcp_p->slhcp = NULL;
  932.  
  933. #ifdef notdef
  934.     if (PPPtrace > 1)
  935.         trace_log(PPPiface,"%s PPP/IPCP Drop route to peer (%s)",
  936.             ifp->name,
  937.             inet_ntoa(ipcp_p->local.work.other));
  938.  
  939.     rt_drop(ipcp_p->local.work.other, (unsigned int)32);
  940. #endif
  941.  
  942.     /* Do downscript if defined */
  943.     doscript(1, ipcp_p->local.work.other);
  944. }
  945.  
  946.  
  947. /************************************************************************/
  948. /* configuration negotiation complete */
  949. static void
  950. ipcp_opening(fsm_p)
  951. struct fsm_s *fsm_p;
  952. {
  953.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  954.     struct iface *ifp =         fsm_p->ppp_p->iface;
  955.     int32 address = ipcp_p->local.work.address;
  956.     int rslots = 0;
  957.     int tslots = 0;
  958.  
  959.     done_set_time = 0;
  960.  
  961.     /* Set our IP address to reflect negotiated option */
  962.     if (address != ifp->addr) {
  963.         /* address not the same as last time */
  964.         if (Ip_addr == 0L) {
  965.             /* no global address */
  966.             Ip_addr = address;
  967.         } else if ( Ip_addr == ifp->addr ) {
  968.             /* global was same as local; must be replaced */
  969.             /* !!! TO DO: reset tcp connections */
  970.             Ip_addr = address;
  971.         }
  972.         ifp->addr = address;
  973.  
  974.         if (PPPtrace > 1)
  975.             trace_log(PPPiface,"%s PPP/IPCP Setting new IP address: %s",
  976.                 ifp->name,
  977.                 inet_ntoa(address));
  978.     }
  979.  
  980. #ifdef notdef
  981.     rt_add(ipcp_p->local.work.other, (unsigned int)32, (int32)0,
  982.         ifp, (int32)1, (int32)0, (char)1);
  983.  
  984.     if (PPPtrace > 1)
  985.         trace_log(PPPiface,"%s PPP/IPCP Add route to peer (%s)",
  986.             ifp->name,
  987.             inet_ntoa(ipcp_p->local.work.other));
  988. #endif
  989.  
  990.     /* free old slhc configuration, if any */
  991.     slhc_free( ipcp_p->slhcp );
  992.     ipcp_p->slhcp = NULL;
  993.  
  994.     if (ipcp_p->local.work.negotiate & IPCP_N_COMPRESS) {
  995.         rslots = ipcp_p->local.work.slots;
  996.     }
  997.     if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS) {
  998.         tslots = ipcp_p->remote.work.slots;
  999.     }
  1000.  
  1001.     if ( rslots != 0 || tslots != 0 ) {
  1002.         ipcp_p->slhcp = slhc_init( rslots, tslots );
  1003.  
  1004.         if (PPPtrace > 1)
  1005.             trace_log(PPPiface,"%s PPP/IPCP Compression enabled;"
  1006.                 " Recv slots = %d, flag = %x;"
  1007.                 " Xmit slots = %d, flag = %x",
  1008.                 ifp->name,
  1009.                 rslots,
  1010.                 ipcp_p->local.work.slot_compress,
  1011.                 tslots,
  1012.                 ipcp_p->remote.work.slot_compress);
  1013.     }
  1014.  
  1015.     /* Do upscript if defined */
  1016.     doscript(0, ipcp_p->local.work.other);
  1017. }
  1018.  
  1019.  
  1020. /************************************************************************/
  1021. /* Check the address against all other assigned addresses */
  1022. static int32
  1023. ipcp_addr_idle(addr)
  1024. int32 addr;
  1025. {
  1026.     struct iface *ifp;
  1027.  
  1028.     /* Check if peer IP address is already in use on another interface */
  1029.     /* !!! need to look at *remote* address, not local! */
  1030.     for (ifp=Ifaces; ifp != NULLIF; ifp = ifp->next) {
  1031.         if (ifp->addr == addr)
  1032.             return 0L;
  1033.     }
  1034.     return addr;
  1035. }
  1036.  
  1037.  
  1038. /************************************************************************/
  1039. /* Assign the next unused address from a pool */
  1040. static int32
  1041. ipcp_poolnext(ipcp_p)
  1042. struct ipcp_s *ipcp_p;
  1043. {
  1044.     int32 i = 1L + ipcp_p->peer_max - ipcp_p->peer_min;
  1045.     int32 nextaddr = 0L;
  1046.  
  1047.     while ( i-- > 0  &&  nextaddr == 0L ) {
  1048.         if (++ipcp_p->local.want.other < ipcp_p->peer_min
  1049.          || ipcp_p->local.want.other > ipcp_p->peer_max)
  1050.             ipcp_p->local.want.other = ipcp_p->peer_min;
  1051.  
  1052.         nextaddr = ipcp_addr_idle(ipcp_p->local.want.other);
  1053.     }
  1054.     return(nextaddr);
  1055. }
  1056.  
  1057.  
  1058. /************************************************************************/
  1059. /* Check if we have a specific IP address to assign to remote peer host */
  1060. /* !!! TO DO: subnet mask, and routing */
  1061. static int32
  1062. ipcp_lookuppeer(peerid)
  1063. char *peerid;
  1064. {
  1065.     char *buf;
  1066.     int32 peer_addr = 0L;
  1067.  
  1068.     if (peerid == NULLCHAR)
  1069.         return 0L;
  1070.  
  1071.     if ( (buf = userlookup( peerid, NULLCHARP, NULLCHARP,
  1072.             NULL, &peer_addr )) != NULLCHAR ) {
  1073.         free(buf);
  1074.     }
  1075.     return(peer_addr);
  1076. }
  1077.  
  1078.  
  1079. /************************************************************************/
  1080. /* Prepare to begin configuration exchange */
  1081. static void
  1082. ipcp_starting(fsm_p)
  1083. struct fsm_s *fsm_p;
  1084. {
  1085.     struct ipcp_s *ipcp_p =        fsm_p->pdv;
  1086.  
  1087.     PPP_DEBUG_ROUTINES("ipcp_starting()");
  1088.  
  1089.     /* If not already set, and we know the name of the peer,
  1090.      * look in login file for an address
  1091.      */
  1092.     if ( ipcp_p->remote.want.address == 0L ){
  1093.         ipcp_p->remote.want.address
  1094.         = ipcp_lookuppeer(fsm_p->ppp_p->peername);
  1095.     }
  1096.  
  1097.     /* If available, get next address from PPP pool */
  1098.     if ((ipcp_p->remote.want.address == 0L)
  1099.      && (ipcp_p->peer_min != 0L)) {
  1100.         ipcp_p->remote.want.address = ipcp_poolnext(ipcp_p);
  1101.     }
  1102.  
  1103.     ipcp_p->local.want.address = fsm_p->ppp_p->iface->addr;
  1104. }
  1105.  
  1106.  
  1107. /************************************************************************/
  1108. static void
  1109. ipcp_free(fsm_p)
  1110. struct fsm_s *fsm_p;
  1111. {
  1112.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  1113.  
  1114.     slhc_free( ipcp_p->slhcp );
  1115. }
  1116.  
  1117.  
  1118. /* Initialize configuration structure */
  1119. void
  1120. ipcp_init(ppp_p)
  1121. struct ppp_s *ppp_p;
  1122. {
  1123.     struct fsm_s *fsm_p = &(ppp_p->fsm[IPcp]);
  1124.     struct ipcp_s *ipcp_p;
  1125.  
  1126.     PPPtrace = ppp_p->trace;
  1127.     PPPiface = ppp_p->iface;
  1128.  
  1129.     PPP_DEBUG_ROUTINES("ipcp_init()");
  1130.  
  1131.     fsm_p->ppp_p = ppp_p;
  1132.     fsm_p->pdc = &ipcp_constants;
  1133.     fsm_p->pdv =
  1134.     ipcp_p = callocw(1,sizeof(struct ipcp_s));
  1135.  
  1136.     /* Set option parameters to first request defaults */
  1137.     ASSIGN( ipcp_p->local.want, ipcp_default );
  1138.     ipcp_p->local.will_negotiate = ipcp_negotiate;
  1139.  
  1140.     ASSIGN( ipcp_p->remote.want, ipcp_default );
  1141.     ASSIGN( ipcp_p->remote.work, ipcp_default);
  1142.     ipcp_p->remote.will_negotiate = ipcp_negotiate;
  1143.  
  1144.     fsm_init(fsm_p);
  1145. }
  1146.  
  1147. static void
  1148. doscript(direction, address)
  1149. int direction;    /* 0 - up, 1 - down */
  1150. int32 address;    /* remote IP address */
  1151.     {
  1152.     extern struct cmds far Cmds[];
  1153.     FILE *fp;
  1154.     char t_addr[16], buffer[100], c, *p1, *p2, filename[100];
  1155.     strcpy(t_addr, inet_ntoa(address));
  1156.     if ((fp = fopen(Scripts, READ_TEXT)) == NULL)
  1157.         return;
  1158.     while (fgets(buffer,99,fp) != NULLCHAR)
  1159.         {
  1160.         if (strlen(buffer) > strlen(t_addr)
  1161.             && strncmp(buffer, t_addr, strlen(t_addr)) == 0
  1162.             && ((c = buffer[strlen(t_addr)]) == ' ')
  1163.                 || c == '\t')
  1164.             {
  1165.             /* Point one after the address */
  1166.             p1 = buffer + strlen(t_addr) + 1;
  1167.             /* Skip the whitespace */
  1168.             while (*p1 ==  ' ' || *p1 == '\t')
  1169.                 p1++;
  1170.             /* Now pointing at the up script */
  1171.             if (direction == 1)
  1172.                 {
  1173.                 /* Wander past the upscript */
  1174.                 while (*p1 && *p1 != ' ' && *p1 != '\t')
  1175.                     p1++;
  1176.                 /* And onto the downscript */
  1177.                 while (*p1 ==  ' ' || *p1 == '\t')
  1178.                     p1++;
  1179.                 }
  1180.             p2 = p1;
  1181.             /* Find the end of this filename */
  1182.             while (*p2 && *p2 != ' ' && *p2 != '\t')
  1183.                 p2++;
  1184.             *p2 = '\0';
  1185.             sprintf(filename, "source %s/%s", Dscripts, p1);
  1186.             cmdparse(Cmds,filename,NULL);
  1187.             break;
  1188.             }
  1189.         }
  1190.     fclose(fp);
  1191.     }
  1192.